from abc import ABC, abstractmethod
import logging
from django.conf import settings
from django.core.mail import send_mail
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer

logger = logging.getLogger(__name__)


# 观察者抽象基类
class CourseObserver(ABC):
    """课程观察者抽象基类"""

    @abstractmethod
    def update(self, course, **kwargs):
        pass


# 主题类，管理观察者并通知它们
class CourseSubject:
    """课程主题类"""

    def __init__(self):
        self._observers = []

    def attach(self, observer):
        """添加观察者"""
        if observer not in self._observers:
            self._observers.append(observer)
        return self

    def detach(self, observer):
        """移除观察者"""
        try:
            self._observers.remove(observer)
        except ValueError:
            pass
        return self

    def notify(self, course, **kwargs):
        """通知所有观察者"""
        for observer in self._observers:
            try:
                observer.update(course, **kwargs)
            except Exception as e:
                logger.error(f"观察者通知失败: {e}")
        return self


# 具体观察者实现 - 通知服务
class NotificationObserver(CourseObserver):
    """通知服务观察者"""

    def update(self, course, **kwargs):
        # 获取所有订阅该课程的用户
        from course.models import CourseSubscription
        subscriptions = CourseSubscription.objects.filter(
            course=course,
            is_active=True
        ).select_related('user')

        if not subscriptions:
            return

        # 准备通知消息
        message = f"您订阅的课程《{course.title}》已更新至版本{course.version}，快来查看吧！"

        # 发送邮件通知
        self.send_email_notifications(subscriptions, message)

        # 发送实时推送通知
        self.send_push_notifications(subscriptions, course, message)

        logger.info(f"已向{subscriptions.count()}位用户发送课程更新通知: {course.title}")

    def send_email_notifications(self, subscriptions, message):
        """发送邮件通知"""
        try:
            recipient_list = [sub.user.email for sub in subscriptions if sub.user.email]

            if recipient_list:
                send_mail(
                    subject="课程更新通知",
                    message=message,
                    from_email=settings.DEFAULT_FROM_EMAIL,
                    recipient_list=recipient_list,
                    fail_silently=True,
                )
        except Exception as e:
            logger.error(f"发送邮件通知失败: {e}")

    def send_push_notifications(self, subscriptions, course, message):
        """发送实时推送通知"""
        try:
            channel_layer = get_channel_layer()

            for subscription in subscriptions:
                # 通过WebSocket发送实时通知
                async_to_sync(channel_layer.group_send)(
                    f"user_{subscription.user.id}",
                    {
                        "type": "course.update",
                        "course_id": course.id,
                        "course_title": course.title,
                        "message": message,
                        "version": course.version
                    }
                )
        except Exception as e:
            logger.error(f"发送推送通知失败: {e}")


# 具体观察者实现 - 数据分析服务
class AnalyticsObserver(CourseObserver):
    """数据分析观察者"""

    def update(self, course, **kwargs):
        # 记录课程更新事件，用于数据分析
        logger.info(f"课程更新分析: 课程ID={course.id}, 版本={course.version}")
        # 这里可以添加更复杂的数据分析逻辑


# 观察者工厂类
class ObserverFactory:
    """观察者工厂类，用于创建和管理观察者"""
    _observers = {}

    @classmethod
    def get_observer(cls, observer_type):
        """获取观察者实例"""
        if observer_type not in cls._observers:
            if observer_type == "notification":
                cls._observers[observer_type] = NotificationObserver()
            elif observer_type == "analytics":
                cls._observers[observer_type] = AnalyticsObserver()
            # 可以添加更多观察者类型
            else:
                raise ValueError(f"未知的观察者类型: {observer_type}")
        return cls._observers[observer_type]

    @classmethod
    def get_all_observers(cls):
        """获取所有观察者实例"""
        return list(cls._observers.values())


# 全局主题实例
course_subject = CourseSubject()


# 初始化默认观察者
def init_default_observers():
    """初始化默认观察者"""
    # 添加通知观察者
    notification_observer = ObserverFactory.get_observer("notification")
    course_subject.attach(notification_observer)

    # 添加数据分析观察者
    analytics_observer = ObserverFactory.get_observer("analytics")
    course_subject.attach(analytics_observer)

    logger.info("默认观察者初始化完成")


# 初始化默认观察者
init_default_observers()